package nongchang.kuaijiecaifu.com.ncapp_android.retrofit;

import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.squareup.okhttp.Cache;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import ezy.lite.exception.SystemException;
import ezy.lite.util.ContextUtil;
import ezy.lite.util.Prefs;
import ezy.lite.util.UI;
import nongchang.kuaijiecaifu.com.ncapp_android.Kuaijie;
import nongchang.kuaijiecaifu.com.ncapp_android.common.activity.BaseActivity;
import nongchang.kuaijiecaifu.com.ncapp_android.common.fragment.BaseFragment;
import nongchang.kuaijiecaifu.com.ncapp_android.retrofit.base.Response;
import retrofit.GsonConverterFactory;
import retrofit.Retrofit;
import retrofit.RxJavaCallAdapterFactory;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

public class API {




    public static final String BASE_URL = "http://kjapp.kuaijiecaifu.com/";
//public static final String BASE_URL = "http://kuaijie.app:8000/";
//    public static final String BASE_URL = "http://kjapp.ngrok.natapp.cn/";
//    public static final String BASE_URL = "http://kjapp.dev/";

    public static final String URL_NEWS = BASE_URL + "news/";
    public static final String URI_HELP = "file:///android_asset/help.html";
    public static final String URI_INVEST = "file:///android_asset/invest.html";
    public static final String URI_REGISTER_PROTOCOL = "file:///android_asset/clause.html";

    private static String UA = "kjapp/1.0 (Linux; U; Android " +
            Build.VERSION.RELEASE + "; " +
//            Build.MODEL + "; " +
            Locale.getDefault().getLanguage() + "-" +
            Locale.getDefault().getCountry().toLowerCase() + ")";
    private static final int OKHTTP_CONNECT_TIMEOUT = 10;
    private static final int OKHTTP_WRITE_TIMEOUT = 10;
    private static final int OKHTTP_READ_TIMEOUT = 10;

    public static Retrofit retrofit;
    private static String _token = null;


    public static OkHttpClient client;
    static {
        File cacheFile = new File(Kuaijie.getAppContext().getCacheDir(), "cache");
        Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb
        client = new OkHttpClient();
        client.setConnectTimeout(OKHTTP_CONNECT_TIMEOUT, TimeUnit.SECONDS);
        client.setWriteTimeout(OKHTTP_WRITE_TIMEOUT, TimeUnit.SECONDS);
        client.setReadTimeout(OKHTTP_READ_TIMEOUT, TimeUnit.SECONDS);
        client.interceptors().add(new ReceivedCookiesInterceptor());
        client.interceptors().add(new AddCookiesInterceptor());
        client.setCache(cache);
//        client.networkInterceptors().add(new StethoInterceptor());
//        client.interceptors().add(new LoggingInterceptor());
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").serializeNulls().create();
        retrofit = new Retrofit.Builder()
                .client(client)
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();


    }



    public static  <T extends Response> Observable.Transformer<T, T> checkOn(BaseFragment fragment) {
        return observable -> observable
                .compose(fragment.bindToLifecycle())
                .compose(_checkOn(fragment.getActivity()));
    }
    public static  <T extends Response> Observable.Transformer<T, T> catchOn(BaseFragment fragment) {
        return observable -> observable
                .compose(fragment.bindToLifecycle())
                .compose(_catchOn(fragment.getActivity()));
    }
    public static  <T extends Response> Observable.Transformer<T, T> checkOn(Context context) {
        if (!(context instanceof BaseActivity)) {
            throw SystemException.wrap(new Exception("API.checkOn : api request need BaseActivity context!"));
        }
        BaseActivity activity = (BaseActivity)context;
        return observable -> observable
                .compose(activity.bindToLifecycle())
                .compose(_checkOn(activity));
    }
    public static  <T extends Response> Observable.Transformer<T, T> catchOn(Context context) {
        if (!(context instanceof BaseActivity)) {
            throw SystemException.wrap(new Exception("API.checkOn : api request need BaseActivity context!"));
        }
        BaseActivity activity = (BaseActivity)context;
        return observable -> observable
                .compose(activity.bindToLifecycle())
                .compose(_catchOn(activity));
    }
    private static  <T extends Response> Observable.Transformer<T, T> _checkOn(Context context) {
        return observable -> observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .onErrorResumeNext(throwable -> _catch(context, throwable))
                .filter(result -> _check(context, result));
    }
    private static  <T extends Response> Observable.Transformer<T, T> _catchOn(Context context) {
        return observable -> observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .onErrorResumeNext(throwable -> _catch(context, throwable));
    }
    private static boolean _check(Context context, Response response) {
        if (response.status == 0) {
            return true;
        }
        if (response.status == 401) {
//            logout();
//            ContextUtil.startActivity(context, AccountLoginActivity.class);
            return false;
        }
        if (!TextUtils.isEmpty(response.message)) {
            UI.showToast(context, response.message);
        }

        return false;
    }
    private static <T> Observable<T> _catch(Context context, Throwable throwable) {
        throwable.printStackTrace();
        Log.e("throwable", throwable.toString());
        return Observable.empty();
    }




    public static class ReceivedCookiesInterceptor implements Interceptor {
        @Override
        public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
            com.squareup.okhttp.Response originalResponse = chain.proceed(chain.request());

            if (!originalResponse.headers("Set-Cookie").isEmpty()) {
                HashSet<String> cookies = new HashSet<>();
                for (String header : originalResponse.headers("Set-Cookie")) {
                    cookies.add(header);
                    Log.i("API", "get cookies:" + header);
                }
//                Prefs.apply(Const.PREF_COOKIES, cookies);
            }

//            originalResponse.body().

            return originalResponse;
        }
    }

    public static class AddCookiesInterceptor implements Interceptor {
        @Override
        public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
            Request.Builder builder = chain.request().newBuilder();
            builder.addHeader("User-Agent", UA);
            builder.addHeader("Accept", "application/json; q=0.5");
            if (_token != null) {
                builder.addHeader("X-TOKEN", API._token);
//                builder.addHeader("X-TOKEN", "134b3d843e1b752a4c3dfe729c143ff1");
            }

//            Set<String> cookies = Prefs.get(Const.PREF_COOKIES, new HashSet<>());
//            for (String cookie : cookies) {
//                builder.addHeader("Cookie", cookie);
//                Log.i("API", "set cookies:" + cookie);
//            }
//            return chain.proceed(builder.build());
            return null;
        }
    }


    /**
     * see http://stackoverflow.com/questions/24952199/okhttp-enable-logs
     */
    private static class LoggingInterceptor implements Interceptor {
        @Override
        public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

            long t1 = System.nanoTime();
            Log.v("OkHttp", String.format("Sending request %s on %s%n%s", request.url(), chain.connection(), request.headers()));

            com.squareup.okhttp.Response response = chain.proceed(request);

            long t2 = System.nanoTime();
            Log.v("OkHttp", String.format("Received response for %s in %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6d, response.headers()));

            return response;
        }
    }
}